home *** CD-ROM | disk | FTP | other *** search
/ Revista CD Expert 8 / Revista CD Expert nº 08 CD1.iso / Utilitarios / Programacao / MS-DOS Interrupt List / inter60e / INTPRINT.C < prev    next >
C/C++ Source or Header  |  1998-07-25  |  64KB  |  2,377 lines

  1. /************************************************************************/
  2. /* INTPRINT.C by Ralf Brown.  Donated to the Public Domain.        */
  3. /* Please do not remove my name from any copies or derivatives.        */
  4. /************************************************************************/
  5. /* Program History:                            */
  6. /*   v1.00  4/23/89  initial public release                */
  7. /*             with 4/30/89 list                    */
  8. /*   v1.10  5/21/89  added -I and -f                    */
  9. /*   v1.11  1/6/90   fixed #endif's for compilers which don't handle    */
  10. /*             labels                        */
  11. /*   v1.20  6/8/90   added -r                        */
  12. /*   v1.30  7/14/90  added -b, tables now stay aligned on odd indents    */
  13. /*   v1.40  10/6/90  added -B based on changes by Naoto Kimura, -w    */
  14. /*   v1.40a 5/6/91   HP LaserJet II support by Russ Herman        */
  15. /*   v1.41  7/9/91   HP PCL support by P.J.Farley III            */
  16. /*   v2.00  9/1/91   modular printer definitions            */
  17. /*             printing multipart interrupt list            */
  18. /*   v2.01  2/9/92   fixed summary entry for non-numeric AX= and AH=    */
  19. /*             smarter page breaks                */
  20. /*   v2.02  2/18/92  bugfix & isxdigit suggested by Aaron West        */
  21. /*   v2.10  3/14/92  updated to handle extra flags in headings        */
  22. /*   v2.11  5/23/92  bugfix pointed out by Joe White            */
  23. /*   v2.20  6/12/92  added -F based on code by Richard Brittain        */
  24. /*             added -H and Panasonic printer def by Lewis Paper    */
  25. /*   v2.21  10/14/92 fixed error in -H/-r interaction            */
  26. /*             updated for new 'Bitmask of' section        */
  27. /*   v2.22   2/15/93 exclude Index: by default, -x to force inclusion    */
  28. /*             changed 'Bitmask of' to 'Bitfields for'        */
  29. /*   v2.23   5/24/93 fix to allow INT/AL= to appear correctly in summary*/
  30. /*   v2.24   7/15/93 -k and infinite-length pages by Bent Lynggaard    */
  31. /*   v3.00  04jun94  -T, -V, and multi-file break section skipping    */
  32. /*             major speedups; checked for BC++3.1 compatibility    */
  33. /*   v3.01  11jun94  bugfix: crashed with -l0 -L1 on lines >=80 chars   */
  34. /*   v3.02  07jan95  bugfix by Mark Shapiro: garbage with -B -PHP_PCL    */
  35. /*   v3.03  14jan95  changes for Borland C++ 4.x size minimization    */
  36. /*   v3.04  25mar95  malloc/sbrk and other bugfixes                */
  37. /*   v3.10  11feb96  category filters by Bent Lynggard            */
  38. /*   v3.11  21dec97  support formatting/summarizing other intlist files */
  39. /*   v3.12  25jul98  support for five-char table numbers        */
  40. /************************************************************************/
  41. /* Recompiling:                                */
  42. /*   Turbo C / Borland C++                        */
  43. /*    tcc -mt -lt -O -a -Z -p -k- intprint                */
  44. /*      bcc -mt -lt -a -d -O1agim -p intprint.c                */
  45. /*   Borland C++ 4.x (as .EXE, from John <tenthumbs@bix.com>)        */
  46. /*    bcc -ms -a -d -O1agim -p intprint.c noehs.lib            */
  47. /************************************************************************/
  48.  
  49. #include <ctype.h>
  50. #include <fcntl.h>
  51. #include <stdio.h>
  52. #include <stdlib.h>
  53. #include <string.h>
  54. #include <sys/stat.h>        /* S_IREAD, S_IWRITE */
  55.  
  56. #define VERSION "3.12"
  57.  
  58. /***********************************************/
  59. /*    portability definitions               */
  60.  
  61. #define _other_        /* assume no system-specific match */
  62.  
  63. /*--------------------------------------------------*/
  64. /* first system: MS-DOS with Turbo/Borland C        */
  65.  
  66. #ifdef __TURBOC__
  67. #  define PROTOTYPES
  68. #  include <alloc.h>
  69. #  include <io.h>    /* open, close, read, lseek, etc. */
  70.    int _Cdecl isatty(int handle) ;
  71.  
  72.    /* definitions to reduce size of executable */
  73.    unsigned int _Cdecl _stklen = 1024 ;
  74.    #define close _close
  75.    #define read _read
  76.    #define write _write
  77.    void _Cdecl _setenvp(void) {} /* don't need environment--don't include it */
  78.    void *_Cdecl malloc(size_t size)
  79.      { void *x = sbrk(size) ; return (x==(char*)-1) ? 0 : x ; }
  80.    void _Cdecl free(void *var) { (void)var ; }
  81.    /* since our free() doesn't do anything, macro it out of existence */
  82.    #define free(p)
  83.  
  84.    #ifdef __BORLANDC__
  85.    void _Cdecl _setupio(void) {}
  86.    #pragma warn -eff
  87.    /* BC++ v3.1 sets __BORLANDC__ to 0x0410!! */
  88.    #if __BORLANDC__ >= 0x0400 && __BORLANDC__ != 0x0410
  89.    /* Changes by John Sasse to minimize executable size */
  90.    #if 1
  91.       /* the preferred way */
  92.       /* Borland claims they "might" stop supporting these functions. Right */
  93.       #define   _close(a)      _rtl_close(a)
  94.       #define   _creat(a,b)    _rtl_creat(a,b)
  95.       #define   _open(a,b)     _rtl_open(a,b)
  96.       #define   _read(a,b,c)   _rtl_read(a,b,c)
  97.       #define   _write(a,b,c)  _rtl_write(a,b,c)
  98.       #if __BORLANDC__ == 0x400
  99.       /* They forgot to change this in 4.00 only */
  100.       #undef    _read
  101.       #endif
  102.    #else
  103.       #pragma warn -obs    /* the easy way */
  104.    #endif /* 1 */
  105.    #endif /* __BORLANDC__ >= 0x400 */
  106.    #endif /* __BORLANDC__ */
  107.  
  108. #undef _other_
  109. #endif /* __TURBOC__ */
  110.  
  111. #ifdef __MSDOS__
  112. #  define LINE_TERMINATOR '\n'
  113. #endif
  114.  
  115. /*--------------------------------------------------*/
  116. /*   Gnu C compiler                                 */
  117.  
  118. #ifdef __GNUC__
  119. #define PROTOTYPES
  120. #define NEED_ITOA
  121. #define NEED_ULTOA
  122. #define NEED_STRUPR
  123. #define NEED_STRNICMP
  124.  
  125. #undef _other_
  126. #endif /* __GNUC__ */
  127.  
  128. /*--------------------------------------------------*/
  129. /*  generic Unix definitions                        */
  130.  
  131. #ifdef unix
  132. #  include <sys/unistd.h>    /* open, close, read, lseek, etc. */
  133. #  include <sysent.h>        /* open, close, read, lseek, etc. */
  134. extern int isatty(int) ;
  135. #  define LINE_TERMINATOR '\n'
  136. #endif
  137.  
  138.  
  139. /*--------------------------------------------------*/
  140. /*  any other system                                */
  141.  
  142. #ifdef _other_
  143. /* unknown compiler/system, so set configuration #defines */
  144. #if 0  /* set to 1 if compiler supports ANSI-style prototypes, 0 otherwise */
  145. #define PROTOTYPES
  146. #endif
  147. #if 1  /* set to 0 if library contains strnicmp(), 1 otherwise */
  148. #define NEED_STRNICMP
  149. #endif
  150. #if 1  /* set to 0 if library contains isxdigit(), 1 otherwise */
  151. #define NEED_ISXDIGIT
  152. #endif
  153. #if 1  /* set to 0 if library contains strupr(), 1 otherwise */
  154. #define NEED_STRUPR
  155. #endif
  156. #if 1  /* set to 0 if library contains three-arg itoa(), 1 otherwise */
  157. #define NEED_ITOA
  158. #endif
  159. #if 1  /* set to 0 if library contains three-arg ultoa(), 1 otherwise */
  160. #define NEED_ULTOA
  161. #endif
  162.  
  163. #endif /* _other_ */
  164.  
  165. /*--------------------------------------------------*/
  166.  
  167. /* the last character of the line termination sequence, i.e. '\n' for CRLF */
  168. /* and LF, '\r' if your system uses CR or LFCR */
  169. #ifndef LINE_TERMINATOR
  170. #define LINE_TERMINATOR '\n'
  171. #endif /* LINE_TERMINATOR */
  172.  
  173. /*--------------------------------------------------*/
  174. /*  catchall for macros which might not be defined  */
  175.  
  176. #ifndef O_BINARY
  177. #  define O_BINARY 0
  178. #endif
  179.  
  180. #ifndef _Cdecl
  181. #  define _Cdecl
  182. #endif
  183.  
  184. /***********************************************/
  185.  
  186. #ifndef FALSE
  187. #define FALSE 0
  188. #endif
  189. #ifndef TRUE
  190. #define TRUE !FALSE
  191. #endif
  192.  
  193. /***********************************************/
  194.  
  195. #define MAXLINE 82   /* at most 80 chars per line (plus CR and newline) */
  196. #define MAXPAGE 200  /* at most 200 lines per page */
  197.  
  198. #define lengthof(x) (sizeof(x)/sizeof(x[0]))
  199.  
  200. #ifdef __MSDOS__
  201. #define chars_to_long(a, b, c, d) \
  202.     (a | (((long)b)<<8) | (((long)c)<<16) | (((long)d)<<24))
  203. #define long_div_line chars_to_long('-','-','-','-')
  204. #define divider_line(line) (((long*)line)[0] == long_div_line && \
  205.   ((long*)line)[1] == long_div_line)
  206. #define index_line(l) \
  207.   (((long*)l)[0]==chars_to_long('I','n','d','e')&& \
  208.    ((short*)l)[2]==('x'+':'*0x100))
  209. #else
  210. static char long_chars[] = "----INT Index:" ;
  211. #define divider_line(line) (((long*)line)[0] == ((long*)long_chars)[0]\
  212.   && ((long*)line)[1] == ((long*)long_chars)[0])
  213. #define index_line(line) (((long*)line)[0] == ((long*)long_chars)[2] && \
  214.   ((short*)line)[2] == (short*)long_chars)[6])
  215. #endif
  216. #define section_start(line) is_keyword(line,section_start_keys,lengthof(section_start_keys))
  217. #define start_of_table(line) (is_keyword(line,table_start_keys,lengthof(table_start_keys)))
  218.  
  219. #define section_file_start(s) (s[0] == '-' && memcmp(s+1,"-------!---Section",18) == 0)
  220.  
  221.  
  222. /* category filters definitions and variables */
  223. #define CF_BUFFER_SIZE 26+26+9
  224. typedef enum {CF_EXCLUDE, CF_UNCONDITIONAL, CF_INCLUDE, CF_OVERRIDE,
  225.     CF_ENUM_SIZE} CF_ENUM; /* leave CF_ENUM_SIZE as the last enumetator */
  226. char cf_buffers[CF_ENUM_SIZE][CF_BUFFER_SIZE+1];
  227. char cf_current_category;
  228. #define CF_EXCLUDE_CHAR '<'
  229. #define CF_UNCONDITIONAL_CHAR '>'
  230. #define CF_INCLUDE_CHAR 'i'
  231. #define CF_OVERRIDE_CHAR 'o'
  232.  
  233. /***********************************************/
  234. /*    stub functions to reduce executable size */
  235. /***********************************************/
  236.  
  237. #ifdef __BORLANDC__
  238. /* Changes by John Sasse */
  239. /* BC++ v3.1 sets __BORLANDC__ to 0x0410!!  */
  240. #if __BORLANDC__ >= 0x0400 && __BORLANDC__ != 0x0410
  241. /*      Everything within this conditional may be placed in
  242.  *      a separate source file if desired.
  243.  */
  244.  
  245. /* stack overflow checking can never be allowed inside
  246.    the run-time library */
  247. #pragma option -N-
  248.  
  249. #include <errno.h>
  250. /* the next 3 include files are necessary only if this
  251.    is compiled as a separate file */
  252. #if 0
  253. #include <io.h>
  254. #include <stdlib.h>
  255. #include <string.h>
  256. #endif
  257.  
  258. /* declarations */
  259. void _Cdecl      __ErrorMessage (const char *__message);
  260. int  pascal near __IOerror (int  _doserror_);
  261. int  pascal near __DOSerror (int  _doserror_);
  262. void _Cdecl      _abort (void);
  263.  
  264.  
  265. /* may be referenced by a lot of things */
  266. int _Cdecl _doserrno = 0;
  267.  
  268. /*
  269.     The _rtl_* functions all call __IOError which originally
  270.     referenced sys_nerr and sys_errlist. Unfortunately, the
  271.     source file for these also contains perror which calls
  272.     fputs. Hence you get lots of extra code.
  273.     This is a very minimal replacement.
  274. */
  275. int pascal near __IOerror(int _doserror_)
  276. {
  277. /* if _doserror_ is < 0, it might be a System V error.
  278.    we don't care */
  279.     _doserrno = (_doserror_ < 0) ? (-1) : _doserror_;
  280.     errno = EIO;        /* a default value */
  281.     return (-1);
  282. }
  283.  
  284. /* __DOSerror and __IOerror are in the same source file.
  285.    This may not actually be called. Better safe ...
  286. */
  287. #if 1
  288. int pascal near __DOSerror(int _doserror_)
  289. {
  290.     __IOerror(_doserror_);
  291.     return (_doserror_);
  292. }
  293. #endif
  294.  
  295. /*
  296.    The startup code, among others, references _setargv which
  297.    references abort. The run-time library version says "raise
  298.    (SIGABRT)", bringing in a lot of unnecessary code.
  299. */
  300. void _Cdecl abort (void)
  301. {
  302.     _abort ();
  303. }
  304.  
  305. /* necessary to avoid referencing _streams */
  306. #if 1
  307. #define STDERR      2
  308.  
  309. void _Cdecl __ErrorMessage(const char *msg)
  310. {
  311.     _rtl_write(STDERR, msg, strlen(msg));
  312. }
  313. #endif
  314.  
  315. /* restore command line state; note the "." */
  316. #pragma option -N.
  317.  
  318. #endif  /* __BORLANDC__ >= 0x400 */
  319. #endif  /* __BORLANDC__ */
  320.  
  321. /***********************************************/
  322. /*    replacement file I/O function macros     */
  323. /***********************************************/
  324.  
  325. typedef struct
  326.    {
  327.    int fd ;
  328.    int buf_maxsize ;
  329.    char *buf ;
  330.    unsigned long bufoffset ;
  331.    int bufsize ;
  332.    int bufpos ;
  333.    int write ;             /* file is output file if nonzero */
  334.    } IP_FILE ;
  335.  
  336. #define ip_putc(c,fp) \
  337.   ((fp)->buf[fp->bufpos++]=(c),\
  338.    ((fp)->bufpos>=(fp)->buf_maxsize&&ip_flush(fp)==-1)?-1:0)
  339.  
  340. /* output the indicated counted string to the given file */
  341. #define ip_putcstr(s,fp) ip_write((s)->str,(s)->len,fp)
  342. /* output the given string literal to the indicated file */
  343. #define ip_putlit(s,fp) ip_write((s),sizeof(s)-1,fp)
  344. /* output the given string variable to the indicated file */
  345. #define ip_puts(s, fp) ip_write(s,strlen(s),fp)
  346.  
  347. #ifdef __MSDOS__
  348. #define newline(fp) ip_write("\r\n",2,fp)
  349. #else
  350. #define newline(fp) ip_putc('\n',fp)
  351. #endif
  352.  
  353. /***********************************************/
  354.  
  355. typedef struct             /* a counted string */
  356.    {
  357.    int len ;             /* the string's length */
  358.    char *str ;             /* the actual contents of the string */
  359.    } cstr ;
  360.  
  361. #define CSTR(s) { sizeof(s)-1, (s) }  /* for defining a counted string literal */
  362. #define cstrlen(s) ((s)->len)     /* how long is the counted string? */
  363.  
  364. typedef struct
  365.    {
  366.    char *name ;            /* for selecting the appropriate printer */
  367.    cstr init1, init2 ;        /* initialization strings */
  368.    cstr marginl, marginc, marginr ; /* margins: duplex even, non-duplex, duplex odd */
  369.    cstr duplex_on ;        /* turn on duplex mode */
  370.    cstr term1, term2 ;        /* cleanup strings */
  371.    cstr bold_on, bold_off ;    /* boldface on/off */
  372.    int indent ;            /* how many extra spaces to indent */
  373.    int lines_per_page ;        /* how many lines to print on each page */
  374.    int page_length ;        /* how many lines on each page */
  375.    int page_width ;        /* how many printable columns per line? */
  376. #ifdef PROTOTYPES
  377.    void (*put_line)(IP_FILE *,int) ;/* function to call to print out divider line */
  378.    void (*set_typeface)(IP_FILE *,char *) ;
  379. #else
  380.    void (*put_line)() ;        /* function to call to print out divider line */
  381.    void (*set_typeface)() ;
  382. #endif /* PROTOTYPES */
  383.    int *flag ;            /* flag to set when using this printer definition */
  384.    } PRINTER_DEF ;
  385.  
  386. typedef struct filter_list
  387.    {
  388.    struct filter_list *next ;
  389.    char str[1] ;        /* will allocate enough for actual string */
  390.    } FILT_LIST ;
  391.  
  392. typedef struct
  393.    {
  394.    int part ;
  395.    int first_on_page ; /* TRUE if a new entry starts at the top of the page */
  396.    char desc[32] ;
  397.    int len ;
  398.    } HEADER ;
  399.  
  400. typedef struct
  401.    {
  402. /*   char *name ;*/
  403.    char name[14] ;
  404.    int length ;
  405.    } KEYWORDS ;
  406.  
  407. /***********************************************/
  408.  
  409. #ifdef PROTOTYPES
  410. void usage(void) ;
  411. void fatal(char *msg) ;
  412. void warning(char *msg) ;
  413. int unwanted_section(char *buf) ;
  414. IP_FILE *ip_fdopen(int fd,char *buf,int bufsiz, int maxsiz, int write) ;
  415. IP_FILE *ip_open_write(char *name, int trunc, char *buf, int bufsiz) ;
  416. IP_FILE *ip_open_read(char *name, char *buf, int bufsiz) ;
  417. int ip_close(IP_FILE *fp) ;
  418. unsigned long ip_fgets(char *buf, int max, IP_FILE *fp) ;
  419. int ip_write(char *buf, int count, IP_FILE *fp) ;
  420. int ip_flush(IP_FILE *fp) ;
  421. void get_raw_line(char *buf) ;
  422. void get_line(char *buf) ;
  423. void indent_to(int where,IP_FILE *fp) ;
  424. void put_line(IP_FILE *fp, int len) ;
  425. void HPPCL_put_line(IP_FILE *fp, int len) ;
  426. void HPPCL_set_typeface(IP_FILE *fp,char *typeface) ;
  427. int start_of_entry(char *s) ;
  428. int is_keyword(char *s, KEYWORDS *keys, unsigned int numkeys) ;
  429. void output_line(char *line,IP_FILE *fp) ;
  430. void fill_buffer(int lines, int lines_per_page) ;
  431. int find_page_break(int lines) ;
  432. int summarize(int line, int pages_printed) ;
  433. void start_format(char *line) ;
  434. void write_summary_header(IP_FILE *fp, char *title, int offsets, int tables) ;
  435. void show_offset(int line,IP_FILE *fp) ;
  436. void add_table(int i) ;
  437. void add_category_filter_info(CF_ENUM filter, char *str) ;
  438. FILT_LIST *add_filter_info(FILT_LIST *list,char *str) ;
  439. void build_filter_lists(char *file) ;
  440. int make_description(char *desc,char *type,int line) ;
  441. char *determine_heading(int last) ;
  442. void print_buffer(int last,int body_lines,int lines_per_page,int total_lines,
  443.           int use_FF) ;
  444. void select_printer(char *name) ;
  445. void display_printers(void) ;
  446. static void reset_printer_and_close(IP_FILE *fp) ;
  447. int _Cdecl main(int argc, char **argv) ;
  448. #else
  449. void put_line() ;
  450. void HPPCL_put_line() ;
  451. void HPPCL_set_typeface() ;
  452. void show_offset() ;
  453. #endif /* PROTOTYPES */
  454.  
  455. /***********************************************/
  456. /*    I/O buffers                   */
  457. /***********************************************/
  458.  
  459. char stderr_buf[1] ;
  460. char filter_buf[256] ;
  461. char infile_buf[8192] ;
  462. char outfile_buf[8192] ;
  463. char summary_buf[4096] ;
  464. char formats_buf[3072] ;
  465. char tables_buf[3072] ;
  466.  
  467. /***********************************************/
  468.  
  469. IP_FILE *err ;
  470. IP_FILE *infile ;
  471. IP_FILE *outfile ;
  472. char *input_file ;
  473. int input_file_namelen ;
  474.  
  475. char buffer[MAXPAGE][MAXLINE] ;
  476. unsigned long line_offsets[MAXPAGE] ;
  477. char num[8] ;
  478. int need_summary ;
  479. char summary_line[2*MAXLINE] ;
  480. int summary_line_len ;
  481.  
  482. int pages_printed = 0 ;
  483. int page_width = 0 ;        /* page width in characters, 0 = use prtdef */
  484. int indent = 0 ;            /* number of columns to indent lines */
  485. char *indent_string = NULL ;    /* what to add at start of line to indent */
  486. int indent_len = 0 ;            /* length of indent_string */
  487. int widow_length = 8 ;        /* number of lines to scan for good place to break */
  488. int page_numbers = FALSE ;    /* add page numbers to bottom of page? */
  489. int multi_file = FALSE ;    /* printing multipart interrupt list? */
  490. int out_of_files = FALSE ;    /* hit end of last file for multipart printing? */
  491. int do_summary = FALSE ;    /* create a one-line-per-call summary? */
  492. int do_tables = FALSE ;        /* create a one-line-per-table index? */
  493. int do_formats = FALSE ;    /* create a separate file with data structures? */
  494. int do_filter = FALSE ;        /* using a filtering file? */
  495. int do_headers = FALSE ;    /* add page headings? */
  496. int include_index_lines = FALSE ;
  497. int IBM_chars = FALSE ;        /* printer can handle IBM graphics characters */
  498. int boldface = FALSE ;        /* boldface titles and Return:/Notes: ? */
  499. int printer_bold = FALSE ;    /* boldface using printer control sequences? */
  500. int echo_format = FALSE ;
  501. int duplex = FALSE ;
  502. int HPPCL_mode = FALSE ;
  503. int show_offsets = FALSE ;
  504. int keep_divider_lines = FALSE ;
  505. int exclude_only = TRUE ;
  506. IP_FILE *summary ;
  507. IP_FILE *tables ;
  508. IP_FILE *formats ;
  509. PRINTER_DEF *printer = NULL ;
  510.  
  511. unsigned long current_line_offset = 0 ;
  512. unsigned long offset_adjust = 0 ;
  513.  
  514. unsigned int first_page = 0 ;
  515. unsigned int last_page = ~0 ;
  516.  
  517. int prev_table = 0 ;
  518.  
  519. FILT_LIST *includes = NULL ;
  520. FILT_LIST *excludes = NULL ;
  521.  
  522. HEADER header_first = { 0, FALSE, "" } ;
  523. HEADER header_last = { 0, FALSE, "" } ;
  524.  
  525. /***********************************************/
  526.  
  527. PRINTER_DEF printers[] =
  528.    {
  529.      { "default",
  530.        CSTR(""), CSTR(""),
  531.        CSTR(""), CSTR(""), CSTR(""),
  532.        CSTR(""),
  533.        CSTR(""), CSTR(""),
  534.        CSTR(""), CSTR(""),
  535.        -1,
  536.        60,
  537.        0,
  538.        79,
  539.        put_line,
  540.        NULL,
  541.        NULL,
  542.      },
  543.      { "Epson FX80, 12 cpi",
  544.        CSTR("\033M"), CSTR(""),
  545.        CSTR("\033l\004"), CSTR("\033l\007"), CSTR("\033l\014"),
  546.        CSTR(""),
  547.        CSTR("\033P"), CSTR("\033l\000"),
  548.        CSTR("\033E"), CSTR("\033F"),
  549.        0,
  550.        60,
  551.        0,
  552.        87,    /* 96 - left margin - 1 right margin */
  553.        put_line,
  554.        NULL,
  555.        NULL,
  556.      },
  557.      { "Panasonic KX-P1124i / 10 cpi Epson",
  558.        CSTR(""), CSTR(""),
  559.        CSTR(""), CSTR(""), CSTR(""),
  560.        CSTR(""),
  561.        CSTR(""), CSTR(""),
  562.        CSTR("\033E"), CSTR("\033F"),
  563.        -1,
  564.        60,
  565.        0,
  566.        79,
  567.        put_line,
  568.        NULL,
  569.        NULL,
  570.      },
  571.      { "HP PCL",
  572.        CSTR("\033(8U"), CSTR(""),
  573.        CSTR("\033&a4c4L"), CSTR("\033&a8c8L"), CSTR("\033&a12c12L"),
  574.        CSTR("\033&l1S"),
  575.        CSTR("\033E"), CSTR(""),
  576.        CSTR("\033(s3B"), CSTR("\033(s0B"),
  577.        0,
  578.        69,
  579.        0,
  580.        87,    /* 96 - left margin - 1 right margin */
  581.        HPPCL_put_line,
  582.        HPPCL_set_typeface,
  583.        &HPPCL_mode,
  584.      },
  585. #define HPPCL_FONT_ON_A "\033(s0p12h10v0s0b"
  586. /* HP PCL4/5 Font select: Roman-8;Upright12Pitch10PointMediumWeight */
  587. #define HPPCL_FONT_ON_B "T\033&l6.8571C"
  588. /* HP PCL4/5 Font select: End typeface select;VMI=7LPI: (48/7)-48th's inches*/
  589. #define HPPCL_IBM_LN_A    "\033&f0S\033*p-15Y\033*c"
  590. /* HP PCL4/5 IBM Line:    Push Pos;Up 15/720";Hor.Rule ???/300ths" long */
  591. #define HPPCL_IBM_LN_B    "a3b0P\033&f1S"
  592. /* HP PCL4/5 IBM Line:     3/300ths" high,Print rule;Pop Position */
  593.      { "LaserJet II",
  594.        CSTR("\033(10U"),CSTR(""),
  595.        CSTR("\033&a4c4L"), CSTR("\033&a8c8L"), CSTR("\033&a12c12L"),
  596.        CSTR(""),
  597.        CSTR("\033E"),CSTR(""),
  598.        CSTR("\033(s3B"),CSTR("\033(s0B"),
  599.        0,
  600.        54,
  601.        60,
  602.        79,
  603.        put_line,
  604.        NULL,
  605.        &IBM_chars,
  606.      },
  607.    } ;
  608. #define NUM_PRINTERS lengthof(printers)
  609.  
  610. /***********************************************/
  611.  
  612. #define KEYWORD_ENTRY(s) { s, sizeof(s)-1 }
  613.  
  614. KEYWORDS section_start_keys[] =
  615.    {
  616.     KEYWORD_ENTRY("BUG:"),
  617.     KEYWORD_ENTRY("BUGS:"),
  618.     KEYWORD_ENTRY("Desc:"),
  619.     KEYWORD_ENTRY("Index:"),
  620.     KEYWORD_ENTRY("Note:"),
  621.     KEYWORD_ENTRY("Notes:"),
  622.     KEYWORD_ENTRY("Program:"),
  623.     KEYWORD_ENTRY("Range:"),
  624.     KEYWORD_ENTRY("Return:"),
  625.     KEYWORD_ENTRY("SeeAlso:"),
  626.    } ;
  627.  
  628. KEYWORDS table_start_keys[] =
  629.    {
  630.     KEYWORD_ENTRY("Bitfields "),
  631.     KEYWORD_ENTRY("Call "),
  632.     KEYWORD_ENTRY("Format "),
  633.     KEYWORD_ENTRY("Values "),
  634.    } ;
  635.  
  636. /***********************************************/
  637.  
  638. #ifdef isxdigit
  639. #undef NEED_ISXDIGIT
  640. #endif
  641.  
  642. #ifdef NEED_STRNICMP
  643. #ifdef PROTOTYPES
  644. int strnicmp(char *s1,char *s2,unsigned int len) ;
  645. #endif
  646. int strnicmp(s1,s2,len)
  647. char *s1,*s2 ;
  648. unsigned int len ;
  649. {
  650.    char c1, c2 ;
  651.  
  652.    while (*s1 && *s2 && len > 0)
  653.       {
  654.       len-- ;
  655.       c1 = (islower(*s1) ? toupper(*s1) : *s1) ;
  656.       c2 = (islower(*s2) ? toupper(*s2) : *s2) ;
  657.       if (c1 != c2 || len == 0)     /* mismatch or substrings exhausted? */
  658.      return (c1 - c2) ;
  659.       s1++ ;
  660.       s2++ ;
  661.       }
  662.    return 0 ;  /* strings match exactly on first 'len' characters */
  663. }
  664. #endif /* NEED_STRNICMP */
  665.  
  666. #ifdef NEED_STRUPR
  667. #ifdef PROTOTYPES
  668. char *strupr(char *s) ;
  669. #endif
  670. char *strupr(s)
  671. char *s ;
  672. {
  673.    char *orig_s = s ;
  674.    char c ;
  675.    
  676.    if (s)
  677.       while (*s)
  678.      {
  679.      c = *s ;      
  680.      *s++ = (islower(c) ? toupper(c) : c) ;
  681.      }
  682.    return orig_s ;
  683. }
  684. #endif /* NEED_STRUPR */
  685.  
  686. #ifdef NEED_ISXDIGIT
  687. #ifdef PROTOTYPES
  688. int isxdigit(int c) ;
  689. #endif
  690. int isxdigit(c)
  691. int c ;
  692. {
  693.    return isdigit(c) || (memchr("ABCDEFabcdef",c,12) != NULL) ;
  694. }
  695. #endif /* NEED_ISXDIGIT */
  696.  
  697. #ifdef NEED_ITOA
  698. #ifdef PROTOTYPES
  699. char *itoa(int num,char *buf,int radix) ;
  700. #endif
  701. char *itoa(num,buf,radix)   /* not everybody has the same itoa() as TurboC */
  702. int num ;            /* minimal implementation */
  703. char *buf ;
  704. int radix ;
  705. {
  706.    int count = 0 ;
  707.    int i ;
  708.    char tmp ;
  709.  
  710.    do {
  711.       buf[count++] = "0123456789ABCDEF"[num % radix] ;
  712.       num /= radix ;
  713.    } while (num) ;
  714.    buf[count] = '\0' ;
  715.    if (count > 1)
  716.       for (i = 0 ; i < count / 2 ; i++)
  717.      {
  718.      tmp = buf[i] ;
  719.      buf[i] = buf[count-i-1] ;
  720.      buf[count-i-1] = tmp ;
  721.      }
  722.    return buf ;
  723. }
  724. #endif /* NEED_ITOA */
  725.  
  726. #ifdef NEED_ULTOA
  727. #ifdef PROTOTYPES
  728. char *ultoa(unsigned long num,char *buf,int radix) ;
  729. #endif
  730. char *ultoa(num,buf,radix)   /* not everybody has the same ultoa() as TurboC */
  731. unsigned long num ;         /* minimal implementation */
  732. char *buf ;
  733. int radix ;
  734. {
  735.    int count = 0 ;
  736.    int i ; 
  737.    char tmp ;
  738.  
  739.    do {
  740.       buf[count++] = "0123456789ABCDEF"[num % radix] ;
  741.       num /= radix ;
  742.    } while (num) ;
  743.    buf[count] = '\0' ;
  744.    if (count > 1)
  745.       for (i = 0 ; i < count / 2 ; i++)
  746.      {
  747.      tmp = buf[i] ;
  748.      buf[i] = buf[count-i-1] ;
  749.      buf[count-i-1] = tmp ;
  750.      }
  751.    return buf ;
  752. }
  753. #endif /* NEED_ULTOA */
  754.  
  755. /***********************************************/
  756.  
  757. void usage()
  758. {
  759.    ip_putlit("\
  760. Usage: intprint [options] intlist [>|>>]output\r\n\
  761. Options:\r\n\
  762. Filtering:\t-Ffile\tprint only entries matching filtering info in 'file'\r\n\
  763. \t\t-k\tkeep original divider lines\r\n\
  764. \t\t-rN:M\tprint only pages N through M\r\n\
  765. \t\t-x\tinclude Index: lines in formatted output\r\n\
  766. Formatting:\t-b\tboldface headings\t-B\tbold with control codes\r\n\
  767. \t\t-d\t(duplex) print even/odd pages with different indents\r\n\
  768. \t\t-e\t(elite) 96 chars/line\t-tN\tselect typeface N\r\n\
  769. Pagination:\t-H\tadd page headers\t-iN\tindent N spaces\r\n\
  770. \t\t-p\tnumber pages\t\t-nN\tN pages already printed\r\n\
  771. \t\t-wN\twidow lines control\r\n\
  772. \t\t-lN\tprint length\t\t-LN\ttotal page length\r\n\
  773. \t\t\t(0 = infinite)\t(use linefeeds if > #lines printed)\r\n\
  774. Printer:\t-I\tIBM graphics characters\r\n\
  775. \t\t-Pname\tassume printer 'name'\t-P?\tlist printers\r\n\
  776. Summaries:\t-ffile\tdata structure formats\t-sfile\tINT calls\r\n\
  777. \t\t-Tfile\tlist tables\r\n\
  778. Misc:\t\t-m\tprocess multiple parts\t-V\tmake INTERVUE summary\r\n\
  779. "
  780.     ,err) ;
  781.    ip_flush(err) ;
  782.    exit(1) ;
  783. }
  784.  
  785. /***********************************************/
  786.  
  787. void fatal(msg)
  788. char *msg ;
  789. {
  790.    ip_putlit("UNRECOVERABLE ERROR:",err) ;
  791.    newline(err) ;
  792.    ip_puts(msg,err) ;
  793.    newline(err) ;
  794.    ip_flush(err) ;
  795.    exit(1) ;
  796. }
  797.  
  798. /***********************************************/
  799.  
  800. void warning(msg)
  801. char *msg ;
  802. {
  803.    ip_putlit("Warning: ",err) ;
  804.    ip_puts(msg,err) ;
  805.    newline(err) ;
  806. }
  807.  
  808. /***********************************************/
  809.  
  810. IP_FILE *ip_fdopen(fd,buf,bufsiz,maxsiz,write)
  811. int fd ;
  812. char *buf ;
  813. int bufsiz, maxsiz, write ;
  814. {
  815.    IP_FILE *fp = (IP_FILE *)malloc(sizeof(IP_FILE)) ;
  816.    
  817.    if (fp)
  818.       {
  819.       fp->fd = fd ;
  820.       fp->buf = buf ;
  821.       fp->bufsize = bufsiz ;
  822.       fp->buf_maxsize = maxsiz ;
  823.       fp->bufpos = 0 ;
  824.       fp->bufoffset = 0 ;
  825.       fp->write = write ;
  826.       }
  827.    return fp ;
  828. }
  829.  
  830. /***********************************************/
  831.  
  832. IP_FILE *ip_open_write(name,trunc,buf,bufsiz)
  833. char *name ;
  834. char *buf ;
  835. int trunc ;
  836. int bufsiz ;
  837. {
  838.    int fd ;
  839.    
  840.    if (name && *name == '\0')
  841.       fd = 1 ;    /* open stdout */
  842.    else
  843.       {
  844. #ifdef __TURBOC__
  845.       if (trunc)
  846.      fd = _creat(name,0) ;     /* create with no attribute bits sets */
  847.       else
  848.      fd = _open(name,O_WRONLY) ;
  849. #else
  850.       if (trunc) trunc = O_TRUNC ;
  851.       fd = open(name,O_WRONLY|O_BINARY|O_CREAT|trunc,S_IREAD|S_IWRITE) ;
  852. #endif
  853.       if (fd == -1)
  854.      return 0 ;
  855.       if (!trunc)
  856.      lseek(fd,0L,SEEK_END) ;
  857.       }
  858.    return ip_fdopen(fd,buf,bufsiz,bufsiz,1) ;
  859. }
  860.  
  861. /***********************************************/
  862.  
  863. IP_FILE *ip_open_read(name,buf,bufsiz)
  864. char *name ;
  865. char *buf ;
  866. int bufsiz ;
  867. {
  868.    int fd, siz ;
  869.  
  870. #ifdef __TURBOC__
  871.    if ((fd = _open(name,O_RDONLY)) != -1)
  872. #else
  873.    if ((fd = open(name,O_RDONLY | O_BINARY,0)) != -1)
  874. #endif
  875.       {
  876.       siz = read(fd,buf,bufsiz) ;
  877.       if (siz == -1)
  878.      return 0 ;
  879.       return ip_fdopen(fd,buf,siz,bufsiz,0) ;
  880.       }
  881.    else
  882.       return 0 ;
  883. }
  884.  
  885. /***********************************************/
  886.  
  887. int ip_flush(fp)
  888. IP_FILE *fp ;
  889. {
  890.    if (fp->write && fp->bufpos)
  891.       {
  892.       if (fp->bufpos > fp->buf_maxsize)
  893.      fp->bufpos = fp->buf_maxsize ;
  894.       if (write(fp->fd,fp->buf,fp->bufpos) == -1)
  895.      return -1 ;
  896.       fp->bufpos = 0 ;
  897.       }
  898.    return 0 ;
  899. }
  900.  
  901. /***********************************************/
  902.  
  903. int ip_close(fp)
  904. IP_FILE *fp ;
  905. {
  906.    if (ip_flush(fp) == -1 || close(fp->fd) == -1)
  907.       return -1 ;
  908.    free(fp) ;
  909.    return 0 ;
  910. }
  911.  
  912. /***********************************************/
  913.  
  914. unsigned long ip_fgets(buf, max, fp)
  915. char *buf ;
  916. int max ;
  917. IP_FILE *fp ;
  918. {
  919.    unsigned long line_offset = fp->bufoffset + fp->bufpos ;
  920.    char *end ;
  921.    int len ;
  922.    int new_bufpos ;
  923.    char *fpbuf = fp->buf ;
  924.    int bufpos = fp->bufpos ;
  925.    
  926.    --max ;
  927.    if (bufpos + max < fp->bufsize)
  928.       {
  929.       end = (char *)memchr(fpbuf+bufpos,LINE_TERMINATOR,max) ;
  930.       if (end)
  931.      {
  932.      new_bufpos = (end-fpbuf) ;
  933.      len = new_bufpos++ - bufpos ;
  934.      /* eradicate rest of multi-character line terminator */
  935.      while (len > 0 && fpbuf[bufpos+len-1] <= ' ')
  936.         len-- ;
  937.      }
  938.       else
  939.      {
  940.      len = max ;
  941.      new_bufpos = bufpos + len ;
  942.      }
  943.       if (len)
  944.      memcpy(buf,fpbuf+bufpos,len) ;
  945.       buf[len] = '\0' ;
  946.       bufpos = new_bufpos ;
  947.       }
  948.    else
  949.       {
  950.       for (len = 1 ; len <= max ; len++)
  951.      {
  952.      *buf = fpbuf[bufpos++] ;
  953.      if (bufpos >= fp->bufsize)
  954.         {
  955.         if (fp->bufsize < fp->buf_maxsize)
  956.            {
  957.            fp->bufsize = bufpos = 0 ;
  958.            fpbuf[0] = '\0' ;  /* dummy value to ensure empty string */
  959.            }
  960.         else
  961.            {
  962.            fp->bufoffset += fp->buf_maxsize ;
  963.            fp->bufsize = read(fp->fd,fpbuf,fp->buf_maxsize) ;
  964.            bufpos = 0 ;
  965.            }
  966.         if (fp->bufsize <= 0)
  967.            {
  968.            line_offset = (unsigned long)-1 ; /* signal end of file */
  969.            if (*buf != LINE_TERMINATOR)
  970.           *buf++ = LINE_TERMINATOR;
  971.            break ;
  972.            }
  973.         }
  974.      if (*buf == LINE_TERMINATOR)
  975.         break ;
  976.      else
  977.         buf++ ;
  978.      }
  979.       if (len > max)       /* did we overflow before hitting EOL? */
  980.      *buf = '\0' ;       /* if yes, plug in the terminator */
  981.       else
  982.      /* eradicate rest of multi-character line terminator */
  983.      while (len-- > 0 && *buf <= ' ')
  984.         *buf-- = '\0' ;
  985.       }
  986.    fp->bufpos = bufpos ;
  987.    return line_offset ;
  988. }
  989.  
  990. /***********************************************/
  991.  
  992. int ip_write(buf, count, fp)
  993. char *buf ;
  994. int count ;
  995. IP_FILE *fp ;
  996. {
  997.    if (fp->bufpos + count < fp->buf_maxsize)
  998.       {
  999.       memcpy(fp->buf+fp->bufpos,buf,count) ;
  1000.       fp->bufpos += count ;
  1001.       }
  1002.    else
  1003.       while (count > 0)
  1004.      {
  1005.      int partial = fp->buf_maxsize - fp->bufpos ;
  1006.  
  1007.      if (count < partial)
  1008.         partial = count ;
  1009.      memcpy(fp->buf+fp->bufpos,buf,partial) ;
  1010.      buf += partial ;
  1011.      fp->bufpos += partial ;
  1012.      count -= partial ;
  1013.      if (fp->bufpos >= fp->buf_maxsize && ip_flush(fp) == -1)
  1014.            return -1 ;
  1015.      }
  1016.    return 0 ;
  1017. }
  1018.  
  1019. /***********************************************/
  1020.  
  1021. #define indent_line(fp) if(indent_string)ip_write(indent_string,indent_len,fp)
  1022.  
  1023. /***********************************************/
  1024.  
  1025. void indent_to(where,fp)
  1026. int where ;
  1027. IP_FILE *fp ;
  1028. {
  1029.    where += indent ;
  1030.    while (where >= 8)
  1031.       {
  1032.       ip_putc('\t',fp) ;
  1033.       where -= 8 ;
  1034.       }
  1035.    if (where)
  1036.       ip_write("        ",where,fp) ;
  1037. }
  1038.  
  1039. /***********************************************/
  1040.  
  1041. void put_line(fp,len)
  1042. IP_FILE *fp ;
  1043. int len ;
  1044. {
  1045.    static char line[8] = { 196, 196, 196, 196, 196, 196, 196, 196 } ;
  1046.  
  1047.    if (IBM_chars)
  1048.       {
  1049.       while (len >= 8)
  1050.      {
  1051.      ip_write(line,8,fp) ;
  1052.      len -= 8 ;
  1053.      }
  1054.       if (len)
  1055.      ip_write(line,len,fp) ;
  1056.       }
  1057.    else
  1058.       {
  1059.       while (len >= 8)
  1060.      {
  1061.      ip_write("--------",8,fp) ;
  1062.      len -= 8 ;
  1063.      }
  1064.       if (len)
  1065.      ip_write("--------",len,fp) ;
  1066.       }
  1067. }
  1068.  
  1069. /***********************************************/
  1070.  
  1071. void HPPCL_put_line(fp,len)
  1072. IP_FILE *fp ;
  1073. int len ;
  1074. {
  1075.    ip_putlit(HPPCL_IBM_LN_A,fp) ;
  1076.    ip_puts(itoa((len * 25), num, 10),fp) ;
  1077.    ip_putlit(HPPCL_IBM_LN_B,fp) ;
  1078. }
  1079.  
  1080. /***********************************************/
  1081.  
  1082. void HPPCL_set_typeface(fp,typeface)
  1083. IP_FILE *fp ;
  1084. char *typeface ;
  1085. {
  1086.    ip_putlit(HPPCL_FONT_ON_A,fp) ;
  1087.    if (typeface)
  1088.       ip_puts(typeface,fp) ;
  1089.    else
  1090.       ip_putlit("8",fp) ;
  1091.    ip_putlit(HPPCL_FONT_ON_B,fp) ;
  1092. }
  1093.  
  1094. /***********************************************/
  1095.  
  1096. int start_of_entry(s)
  1097. char *s ;
  1098. {
  1099.    if (!*s || !isupper(*s))
  1100.       return 0 ;
  1101.    return memcmp(s,"INT ",4) == 0 ||
  1102.       memcmp(s,"PORT ",5) == 0 ||
  1103.       memcmp(s,"CMOS ",5) == 0 ||
  1104.       memcmp(s,"MEM ",4) == 0 ||
  1105.       memcmp(s,"I2C ",4) == 0 ||
  1106.       memcmp(s,"CALL ",5) == 0 ||
  1107.       memcmp(s,"OPCODE ",7) == 0 ||
  1108.       memcmp(s,"MSR ",4) == 0 ;
  1109. }
  1110.  
  1111. /***********************************************/
  1112.  
  1113. int is_keyword(s,keys,numkeys)
  1114. char *s ;
  1115. KEYWORDS *keys ;
  1116. unsigned int numkeys ;
  1117. {
  1118.    register int cmp ;
  1119.    register unsigned int i ;
  1120.    KEYWORDS *currkey ;
  1121.    int firstchar = *s ;
  1122.  
  1123.    do {
  1124.       i = numkeys / 2 ;
  1125.       currkey = &keys[i] ;
  1126.       cmp = (firstchar - currkey->name[0]) ;
  1127.       if (cmp == 0)
  1128.          cmp = memcmp(s,currkey->name,currkey->length) ;
  1129.       if (cmp < 0)
  1130.      numkeys = i ;
  1131.       else if (cmp > 0)
  1132.      {
  1133.      keys = currkey+1 ;
  1134.      numkeys -= i+1 ;
  1135.      }
  1136.       else
  1137.      return TRUE ;
  1138.       } while (numkeys) ;
  1139.    return FALSE ;
  1140. }
  1141.  
  1142. /***********************************************/
  1143.  
  1144. void output_line(line,fp)
  1145. char *line ;
  1146. IP_FILE *fp ;
  1147. {
  1148.    if (*line)
  1149.       {
  1150.       int pos = 0 ;
  1151.       int len = strlen(line) ;
  1152.       
  1153.       indent_line(fp) ;
  1154.       if (boldface)
  1155.      {
  1156.      if (start_of_entry(line) || start_of_table(line))
  1157.         {
  1158.         if (printer_bold)
  1159.            {
  1160.            ip_putcstr(&printer->bold_on,fp) ;
  1161.            ip_write(line,len,fp) ;
  1162.            ip_putcstr(&printer->bold_off,fp) ;
  1163.            newline(fp) ;
  1164.            return ;
  1165.            }
  1166.         else
  1167.            {
  1168.            ip_write(line,len,fp) ;
  1169.            ip_putc('\r',fp) ;
  1170.            indent_line(fp) ;
  1171.            }
  1172.         }
  1173.      else if (section_start(line))
  1174.         {
  1175.         pos = (char *)memchr(line,':',len) - line ;
  1176.         if (printer_bold)
  1177.            {
  1178.            ip_putcstr(&printer->bold_on,fp) ;
  1179.            ip_write(line,pos,fp) ;
  1180.            ip_putcstr(&printer->bold_off,fp) ;
  1181.            line += pos ;       /* adjust because no longer at left edge */
  1182.            len -= pos ;
  1183.            }
  1184.         else
  1185.            {
  1186.            ip_write(line,pos,fp) ;
  1187.            ip_putc('\r',fp) ;
  1188.            indent_line(fp) ;
  1189.            }
  1190.         }
  1191.      } /* boldface */
  1192.       if (indent & 7)  /* indenting by other than a multiple of 8 ? */
  1193.      {
  1194.      while (*line)
  1195.         {
  1196.         if (*line == '\t')
  1197.            {
  1198.            ip_write("        ",8-(pos&7),fp) ;
  1199.            pos = 0 ;   /* absolute column doesn't matter, only mod 8 */
  1200.            }
  1201.         else
  1202.            {
  1203.            ip_putc(*line,fp) ;
  1204.            pos++ ;
  1205.            }
  1206.         line++ ;
  1207.         }
  1208.      }
  1209.       else
  1210.      ip_write(line,len,fp) ;
  1211.       }
  1212.    newline(fp) ;
  1213. }
  1214.  
  1215. /***********************************************/
  1216.  
  1217. void get_raw_line(buf)
  1218. char *buf ;
  1219. {
  1220.    static char progress_indicator[] = "ii\r";
  1221.    IP_FILE *in ;
  1222.  
  1223.    buf[0] = '\0' ;
  1224.    if (out_of_files)
  1225.       return ;
  1226.    current_line_offset = ip_fgets(buf,MAXLINE,infile) ;
  1227.    if (current_line_offset == (unsigned long)-1)
  1228.       if (multi_file)
  1229.      {
  1230.      offset_adjust += lseek(infile->fd,0L,SEEK_END) ;
  1231.      input_file[input_file_namelen-1]++ ;
  1232.      ip_close(infile) ;
  1233.      if ((in = ip_open_read(input_file,infile_buf,sizeof(infile_buf)))
  1234.            != NULL)
  1235.         {
  1236.         infile = in ;
  1237.         current_line_offset = ip_fgets(buf,MAXLINE,infile) ;
  1238.         }
  1239.      else
  1240.         {
  1241.         out_of_files = TRUE ;
  1242.         return ;
  1243.         }
  1244.      }
  1245.       else
  1246.      out_of_files = TRUE ;
  1247.    if (start_of_entry(buf) && ((short*)buf)[2] != ((short*)progress_indicator)[0])
  1248.       {
  1249.       ((short*)progress_indicator)[0] = ((short*)buf)[2] ;
  1250.       ip_putlit(progress_indicator, err) ;
  1251.       }
  1252. }
  1253.  
  1254. /***********************************************/
  1255.  
  1256. int unwanted_section(buf)
  1257. char *buf ;
  1258. {
  1259.    char str[MAXLINE] ;
  1260.    FILT_LIST *p ;
  1261.  
  1262.    strcpy(str,buf) ;
  1263.    (void) strupr(str) ;
  1264.    if (strchr(cf_buffers[CF_EXCLUDE], cf_current_category))
  1265.       return TRUE ; /* section is not wanted */
  1266.    if (exclude_only)
  1267.       goto test_exclude ;
  1268.       /* include the section unless it is header-excluded */
  1269.    if (strchr(cf_buffers[CF_UNCONDITIONAL], cf_current_category))
  1270.       return FALSE ; /* section is unconditionally wanted */
  1271.    if (strchr(cf_buffers[CF_INCLUDE], cf_current_category))
  1272.       goto test_exclude ; /* section is wanted if not header-excluded */
  1273.    /* section may be wanted if an include string matches */
  1274.    for (p = includes ; p ; p = p->next)
  1275.       if (p->str && strstr(str, p->str) != NULL)
  1276.      goto test_exclude ;
  1277.    return TRUE ; /* no include match, the entry is not wanted */
  1278. test_exclude:
  1279.    if (strchr(cf_buffers[CF_OVERRIDE], cf_current_category))
  1280.       return FALSE ; /* overriding header exclutions, section wanted */
  1281.    /* if wanted here, set to TRUE if *any* exclude string matches */
  1282.    for (p = excludes ; p ; p = p->next)
  1283.       if (p->str && strstr(str, p->str) != NULL)
  1284.      return TRUE ;
  1285.    return FALSE ; /* not excluded, the section is wanted */
  1286. }
  1287.  
  1288. /***********************************************/
  1289.  
  1290. void get_line(buf)
  1291. char *buf ;
  1292. {
  1293.    static char next_line[MAXLINE] ;
  1294.    static int readahead = FALSE ;
  1295.  
  1296.    /* get the next line from the file, skipping unwanted entries */
  1297.    if (readahead)
  1298.       {
  1299.       strcpy(buf,next_line) ;
  1300.       readahead = FALSE ;
  1301.       }
  1302.    else
  1303.       {
  1304.       do {
  1305.      get_raw_line(buf) ;
  1306.      } while (!include_index_lines && index_line(buf)) ;
  1307.       if (section_file_start(buf))
  1308.      do {
  1309.         get_raw_line(buf) ;
  1310.         } while (!divider_line(buf)) ;
  1311.       if (do_filter && divider_line(buf))
  1312.      {
  1313.      /* if we read a divider line while filtering, we have to look ahead */
  1314.      strcpy(next_line,buf);
  1315.      while (divider_line(next_line))
  1316.         {
  1317.         strcpy(buf,next_line) ; /* we may be returning the divider */
  1318.         get_raw_line(next_line) ;
  1319.         if (start_of_entry(next_line)) /* is it an interrupt entry? */
  1320.            {
  1321.            cf_current_category = buf[8]; /* save the category character */
  1322.            if (unwanted_section(next_line))
  1323.               {
  1324.               while (!divider_line(next_line))
  1325.              get_raw_line(next_line) ;
  1326.               }
  1327.            else /* section is wanted, so return divider and then next line */
  1328.               readahead = TRUE ;
  1329.            }
  1330.         else
  1331.            readahead = TRUE ;
  1332.         }
  1333.      }
  1334.       }
  1335. }
  1336.  
  1337. /***********************************************/
  1338.  
  1339. void fill_buffer(lines,lines_per_page)
  1340. int lines, lines_per_page ;
  1341. {
  1342.    int i ;
  1343.  
  1344.    /* copy remainder, if any, from last page to top of current page */
  1345.    if (lines)
  1346.       for (i = lines ; i < lines_per_page ; i++)
  1347.      {
  1348.      strcpy(buffer[i-lines], buffer[i]) ;
  1349.      line_offsets[i-lines] = line_offsets[i] ;
  1350.      }
  1351.    else
  1352.       lines = lines_per_page ;
  1353.    for (i = lines_per_page - lines ; i < lines_per_page ; i++)
  1354.       {
  1355.       get_line(buffer[i]) ;
  1356.       line_offsets[i] = current_line_offset + offset_adjust ;
  1357.       }
  1358. }
  1359.  
  1360. /***********************************************/
  1361.  
  1362. int find_page_break(lines)
  1363. int lines ;
  1364. {
  1365.    int i ;
  1366.    char *buf ;
  1367.  
  1368.    for (i = 0 ; i < widow_length ; i++)
  1369.       {
  1370.       buf = buffer[lines-i-1] ;
  1371.       if (buf[0] == '\0' || divider_line(buf))
  1372.      return lines - i ;
  1373.       else if (section_start(buf))
  1374.      return lines - i - 1 ;
  1375.       }
  1376.    return lines ;
  1377. }
  1378.  
  1379. /***********************************************/
  1380.  
  1381. int summarize(line, pages_printed)
  1382. int line, pages_printed ;
  1383. {
  1384.    char *s, reg ;
  1385.    int i ;
  1386.    int max_descrip ;
  1387.    int len, numlen ;
  1388.    int is_INT_entry = 0 ;
  1389.    
  1390.    s = buffer[line] ;
  1391.    if (start_of_entry(s))
  1392.       {
  1393.       memcpy(summary_line," -- -- -- ",10) ;
  1394.       if (s[0] == 'I' && s[1] == 'N')
  1395.      is_INT_entry = 1 ;
  1396.       if (is_INT_entry)
  1397.      {
  1398.      summary_line[1] = s[4] ;     /* output interrupt number */
  1399.      summary_line[2] = s[5] ;
  1400.      len = 4 ;
  1401.      s = buffer[line+1] ;
  1402.      while (*s && isspace(*s))
  1403.         s++ ;
  1404.      if (*s == 'A')
  1405.         {
  1406.         reg = s[1] ;
  1407.         while (*s && *s != '=')
  1408.            s++ ;
  1409.         s++ ;        /* skip the equal sign */
  1410.         while (*s && isspace(*s))
  1411.            s++ ;    /* skip the space between equal sign and number */
  1412.         if (isxdigit(*s) && isxdigit(s[1]))
  1413.            {
  1414.            if (reg == 'L')
  1415.           len += 3 ;
  1416.            summary_line[len++] = *s++ ;
  1417.            summary_line[len++] = *s++ ;
  1418.            if (reg == 'X')
  1419.           {
  1420.           len++ ;
  1421.           summary_line[len++] = *s++ ;
  1422.           summary_line[len] = *s ;
  1423.           }
  1424.            }
  1425.         }
  1426.      }
  1427.       else if (s[0] == 'C' && s[1] == 'M')
  1428.      {
  1429.      summary_line[1] = s[5] ;
  1430.      summary_line[2] = s[6] ;
  1431.      }
  1432.       else if (s[0] == 'M' && s[1] == 'E')
  1433.      {
  1434.      memcpy(summary_line+1,s+4,4) ;
  1435.      if (s[8] == 'h' && s[9] == ':')
  1436.         memcpy(summary_line+5,s+10,4) ;
  1437.      else
  1438.         memcpy(summary_line+5,s+8,4) ;
  1439.      }
  1440.       else if (s[0] == 'I' && s[1] == '2')
  1441.      {
  1442.      summary_line[1] = s[4] ;    /* output bus address */
  1443.      summary_line[2] = s[5] ;
  1444.      if (s[7] == '/')
  1445.         {
  1446.         summary_line[4] = s[8] ;
  1447.         summary_line[5] = s[9] ;
  1448.         if (s[10] != 'h')
  1449.            {
  1450.            summary_line[7] = s[10] ;
  1451.            summary_line[8] = s[11] ;
  1452.            }
  1453.         else if (s[11] == '/')
  1454.            {
  1455.            summary_line[7] = s[12] ;
  1456.            summary_line[8] = s[13] ;
  1457.            }
  1458.         }
  1459.      }
  1460.       len = 10 ;
  1461.       if (page_numbers)
  1462.      {
  1463.      itoa(pages_printed,num,10) ;
  1464.      numlen = strlen(num) ;
  1465.      for (i = numlen ; i < 3 ; i++)
  1466.         summary_line[len++] = ' ' ;
  1467.      memcpy(summary_line+len,num,numlen) ;
  1468.      len += numlen ;
  1469.      summary_line[len++] = ' ' ;
  1470.      }
  1471.       s = buffer[line] + 7 ;    /* find function description */
  1472.       if (!is_INT_entry)
  1473.      {
  1474.      while (*s && !isspace(*s))
  1475.         s++ ;
  1476.      s++ ;
  1477.      }
  1478.       if (*s && *s != '-')    /* does the heading contain flags? */
  1479.      {
  1480.      while (*s && !isspace(*s))
  1481.         summary_line[len++] = *s++ ;
  1482.      summary_line[len++] = '>' ;
  1483.      summary_line[len++] = ' ' ;
  1484.      while (*s && *s != '-')
  1485.         s++ ;
  1486.      }
  1487.       while (*s && !isspace(*s))
  1488.      s++ ;
  1489.       while (*s && isspace(*s))
  1490.      s++ ;
  1491.       max_descrip = (page_width > sizeof(summary_line)-1)
  1492.             ? sizeof(summary_line)-1
  1493.             : page_width ;
  1494.       while (len < max_descrip && *s)
  1495.      summary_line[len++] = *s++ ;
  1496.       summary_line[len] = '\0' ;
  1497.       summary_line_len = len ;
  1498.       return 1 ;
  1499.       }
  1500.    else
  1501.       return 0 ;
  1502. }
  1503.  
  1504. /***********************************************/
  1505.  
  1506. void start_format(line)
  1507. char *line ;
  1508. {
  1509.    indent_line(formats) ;
  1510.    (*printer->put_line)(formats,79) ;
  1511.    newline(formats) ;
  1512.    indent_line(formats) ;
  1513.    ip_puts(summary_line,formats) ;
  1514.    newline(formats) ;
  1515.    indent_line(formats) ;
  1516.    ip_putc('\t',formats) ;
  1517.    ip_puts(line+10,formats) ;
  1518.    newline(formats) ;
  1519.    echo_format = TRUE ;
  1520. }
  1521.  
  1522. /***********************************************/
  1523.  
  1524. void show_offset(line,fp)
  1525. int line ;
  1526. IP_FILE *fp ;
  1527. {
  1528.    char offset_string[12] ;
  1529.    int len ;
  1530.    
  1531.    ultoa(line_offsets[line],offset_string,16) ;
  1532.    len = strlen(offset_string) ;
  1533.    ip_write("00000000",8-len,fp) ;
  1534.    ip_write(offset_string,len,fp) ;
  1535. }
  1536.  
  1537. /***********************************************/
  1538.  
  1539. void add_table(i)
  1540. int i ;
  1541. {
  1542.    char firstchar ;
  1543.    char num[6] ;
  1544.    char *end ;
  1545.    int len ;
  1546.    int summary_width ;
  1547.    int offset = 0 ;
  1548.    char found = FALSE ;
  1549.  
  1550.    prev_table++ ;
  1551.    firstchar = buffer[i][0] ;
  1552.    if (firstchar == 'C' || firstchar == 'V')  /* Call.. or Values... ? */
  1553.       {
  1554.       if (i > 0 && buffer[i-1][0] == '(')
  1555.      {
  1556.      memcpy(num,buffer[i-1]+7,5) ;
  1557.      if (isdigit(num[4]))
  1558.         len = 5 ;
  1559.      else
  1560.         len = 4 ;
  1561.      num[len] = '\0' ;
  1562.      found = TRUE ;
  1563.      if (firstchar == 'V') offset = 11 ;
  1564.      }
  1565.       }
  1566.    else if (firstchar == 'B' || firstchar == 'F') /* Bitfields.. or Format..? */
  1567.       {
  1568.       end = strrchr(buffer[i+1]+7,'(') ;   /* rule out Bit(s) as only match */
  1569.       if (end)
  1570.      {
  1571.      memcpy(num,end+7,5) ;
  1572.      if (isdigit(num[4]))
  1573.         len = 5 ;
  1574.      else
  1575.         len = 4 ;
  1576.      num[len] = '\0' ;
  1577.      found = TRUE ;
  1578.      if (firstchar == 'B')
  1579.         offset = 14 ;
  1580.      else
  1581.         offset = 10 ;
  1582.      }
  1583.       }
  1584.    if (!found)
  1585.       {
  1586.       itoa(prev_table,num,10) ;
  1587.       len = strlen(num) ;
  1588.       }
  1589.    indent_line(tables) ;
  1590.    if (show_offsets)
  1591.       show_offset(i,tables) ;
  1592.    ip_write("  0000",6-len,tables) ;
  1593.    ip_write(num,len,tables);
  1594.    if (page_numbers)
  1595.       {
  1596.       summary_width = 13 ;
  1597.       while (summary_line[summary_width] != ' ')
  1598.      summary_width++ ;
  1599.       summary_width++ ;    /* include the blank we found */
  1600.       }
  1601.    else
  1602.       summary_width = 10 ;
  1603.    ip_write(summary_line,summary_width,tables) ;
  1604.    len = strlen(buffer[i]+offset)-1 ;
  1605.    if (len > page_width - summary_width - 5)
  1606.       len = page_width - summary_width - 5 ;
  1607.    if (len > 0)
  1608.       ip_write(buffer[i]+offset,len,tables) ;
  1609.    newline(tables) ;
  1610. }
  1611.  
  1612. /***********************************************/
  1613.  
  1614. int make_description(desc,type,line)
  1615. char *desc, *type ;
  1616. int line ;
  1617. {
  1618.    char *start = desc ;
  1619.    
  1620.    summarize(line,pages_printed) ;
  1621.    if (type)
  1622.       {
  1623.       int len = strlen(type) ;
  1624.       char *blank = strchr(type,' ') ;
  1625.       if (blank)
  1626.      len = blank - type + 1 ;
  1627.       memcpy(desc,type,len) ;
  1628.       desc += len ;
  1629.       }
  1630.    else
  1631.       {
  1632.       memcpy(desc,"INT ", 4) ;
  1633.       desc += 4 ;
  1634.       }
  1635.    *desc++ = summary_line[1] ;
  1636.    *desc++ = summary_line[2] ;
  1637.    if (summary_line[4] != '-')
  1638.       {
  1639.       memcpy(desc,", AH=", 5) ;
  1640.       desc += 5 ;
  1641.       *desc++ = summary_line[4] ;
  1642.       *desc++ = summary_line[5] ;
  1643.       }
  1644.    if (summary_line[7] != '-')
  1645.       {
  1646.       memcpy(desc,", AL=", 5) ;
  1647.       desc += 5 ;
  1648.       *desc++ = summary_line[7] ;
  1649.       *desc++ = summary_line[8] ;
  1650.       }
  1651.    *desc = '\0' ;
  1652.    return (desc-start)+1 ;
  1653. }
  1654.  
  1655. /***********************************************/
  1656.  
  1657. char *determine_heading(last)
  1658. int last ;
  1659. {
  1660.    int i ;
  1661.    static char heading[MAXLINE] ;
  1662.    char save[25] ;
  1663.    char num[10] ;
  1664.  
  1665.    /* ugly hack to keep the combination of -H and -T from showing wrong page */
  1666.    /* numbers for tables--copy last summary line from previous page to safe */
  1667.    /* place before processing current page, then restore it */
  1668.    memcpy(save,summary_line,sizeof(save)) ;
  1669.    if (start_of_entry(buffer[0]))
  1670.       {
  1671.       header_first.len = make_description(header_first.desc,buffer[0],0) ;
  1672.       header_first.part = 1 ;
  1673.       header_first.first_on_page = TRUE ;
  1674.       }
  1675.    else if (header_last.part == 0)  /* very first entry? */
  1676.       {
  1677.       for (i = 0 ; i < last ; i++)
  1678.      if (start_of_entry(buffer[i]))
  1679.         {
  1680.         header_first.len = make_description(header_first.desc,buffer[i],i);
  1681.         header_first.part = 1 ;
  1682.         header_first.first_on_page = TRUE ;
  1683.         break ;
  1684.         }
  1685.       }
  1686.    else
  1687.       {
  1688.       header_first.len = header_last.len ;
  1689.       memcpy(header_first.desc,header_last.desc,header_last.len) ;
  1690.       header_first.part = header_last.part + 1 ;
  1691.       header_first.first_on_page = FALSE ;
  1692.       }
  1693.    /* assume entry spans entire page */
  1694.    header_last.len = header_first.len ;
  1695.    memcpy(header_last.desc,header_first.desc,header_first.len) ;
  1696.    header_last.part = header_first.part ;
  1697.    header_last.first_on_page = header_first.first_on_page ;
  1698.    /* find last entry on page */
  1699.    if (header_first.part > 0)
  1700.       {
  1701.       for (i = last-1 ; i > 0 ; i--)
  1702.      if (start_of_entry(buffer[i]))
  1703.         {
  1704.         header_last.len = make_description(header_last.desc,buffer[i],i) ;
  1705.         header_last.part = 1 ;
  1706.         header_last.first_on_page = FALSE ;
  1707.         break ;
  1708.         }
  1709.       memcpy(heading,header_first.desc,header_first.len) ;
  1710.       if (header_first.part > 1)
  1711.      {
  1712.      strcat(heading," (Part ") ;
  1713.      strcat(heading,itoa(header_first.part,num,10)) ;
  1714.      strcat(heading,")") ;
  1715.      }
  1716.       if (memcmp(header_first.desc,header_last.desc,header_last.len) != 0 ||
  1717.       header_first.part != header_last.part)
  1718.      {
  1719.      strcat(heading," to ") ;
  1720.      strcat(heading,header_last.desc) ;
  1721.      if (header_last.part > 1)
  1722.         {
  1723.         strcat(heading," (Part ") ;
  1724.         strcat(heading,itoa(header_last.part,num,10)) ;
  1725.         strcat(heading,")") ;
  1726.         }
  1727.      }
  1728.       memcpy(summary_line,save,sizeof(save)) ;
  1729.       return heading ; 
  1730.       }
  1731.    else /* no headings yet */
  1732.       {
  1733.       memcpy(summary_line,save,sizeof(save)) ;
  1734.       return NULL ;
  1735.       }
  1736. }
  1737.  
  1738. /***********************************************/
  1739.  
  1740. void print_buffer(last,body_lines,lines_per_page,total_lines,use_FF)
  1741. int last, body_lines, lines_per_page, total_lines ;
  1742. int use_FF ;
  1743. {
  1744.    int i, len ;
  1745.    int headpos ;
  1746.    int print_this_page = (pages_printed>=first_page && pages_printed<=last_page);
  1747.    
  1748.    pages_printed++ ;
  1749.    if (do_headers)
  1750.       {
  1751.       char *heading ;
  1752.       
  1753.       if ((heading = determine_heading(last)) != NULL)
  1754.      {
  1755.      if (print_this_page)
  1756.         {
  1757.         len = strlen(heading) ;
  1758.         headpos = 40-len/2 ;
  1759.         indent_to(headpos,outfile) ;
  1760.         if (boldface)
  1761.            {
  1762.            if (printer_bold)
  1763.           {
  1764.           ip_putcstr(&printer->bold_on,outfile) ;
  1765.           ip_write(heading,len,outfile) ;
  1766.           ip_putcstr(&printer->bold_off,outfile) ;
  1767.           }
  1768.            else
  1769.           {
  1770.           ip_write(heading,len,outfile) ;
  1771.           ip_putc('\r',outfile) ;
  1772.           indent_to(headpos,outfile) ;
  1773.           ip_write(heading,len,outfile) ;
  1774.           }
  1775.            }
  1776.         else
  1777.            ip_write(heading,len,outfile) ;
  1778.         }
  1779.      }
  1780.       newline(outfile) ;
  1781.       newline(outfile) ;
  1782.       }
  1783.    for (i = 0 ; i < last ; i++)
  1784.       {
  1785.       if (print_this_page)
  1786.      {
  1787.      char *line = buffer[i] ;
  1788.      if (*line)
  1789.         {
  1790.         if (!keep_divider_lines && divider_line(line))
  1791.            {
  1792.            indent_line(outfile) ;
  1793.            (*printer->put_line)(outfile,79) ;
  1794.            newline(outfile) ;
  1795.            echo_format = FALSE ;
  1796.            }
  1797.         else
  1798.            {
  1799.            output_line(line, outfile) ;
  1800.            if (echo_format)
  1801.           output_line(line,formats) ;
  1802.            }
  1803.         }
  1804.      else
  1805.         {
  1806.         newline(outfile) ;
  1807.         echo_format = FALSE ;
  1808.         }
  1809.      }
  1810.       /* need summary lines if doing summary, formats, or table index */
  1811.       if (need_summary)
  1812.      {
  1813.      if (summarize(i,pages_printed) && do_summary && summary)
  1814.         {
  1815.         if (show_offsets)
  1816.            show_offset(i,summary) ;
  1817.         ip_write(summary_line,summary_line_len,summary) ;
  1818.         newline(summary) ;
  1819.         }
  1820.      if (do_formats && memcmp(buffer[i],"Format ",7) == 0)
  1821.         start_format(buffer[i]) ;
  1822.      if (do_tables && start_of_table(buffer[i]))
  1823.         add_table(i) ;
  1824.      }
  1825.       }
  1826.    if (print_this_page)
  1827.       {
  1828.       if (page_numbers)
  1829.      {
  1830.      for (i = last ; i <= body_lines ; i++)
  1831.         newline(outfile) ;
  1832.      itoa(pages_printed, num, 10) ;
  1833.      i = strlen(num) ;
  1834.      if (!duplex)
  1835.         indent_to(38-i/2,outfile) ;
  1836.      else if (pages_printed & 1)        /* odd-numbered page? */
  1837.         indent_to(75-i/2,outfile) ;
  1838.      else
  1839.         indent_to(2,outfile) ;
  1840.      ip_putlit("- ", outfile) ;
  1841.      ip_write(num, i, outfile) ;
  1842.      ip_putlit(" -", outfile) ;
  1843.      newline(outfile) ;
  1844.      }
  1845.       if (use_FF)
  1846.      ip_putc('\f',outfile) ;
  1847.       else
  1848.      for (i = page_numbers?lines_per_page:last ; i<total_lines ; i++)
  1849.         newline(outfile) ;
  1850.       if (duplex)
  1851.      {
  1852.      if (pages_printed & 1)           /* next page even or odd? */
  1853.         ip_putcstr(&printer->marginl, outfile) ;    /* even page */
  1854.      else
  1855.         ip_putcstr(&printer->marginr, outfile) ;    /* odd page */
  1856.      }
  1857.       }
  1858. }
  1859.  
  1860. /***********************************************/
  1861.  
  1862. void display_printers()
  1863. {
  1864.    int i ;
  1865.    
  1866.    ip_putlit("Valid printer names are:",err) ;
  1867.    newline(err) ;
  1868.    for (i = 0 ; i < NUM_PRINTERS ; i++)
  1869.       {
  1870.       ip_putc('\t',err) ;
  1871.       ip_puts(printers[i].name,err) ;
  1872.       newline(err) ;
  1873.       }
  1874.    ip_putlit("When entering the printer name, use either a dash or an",err) ;
  1875.    newline(err) ;
  1876.    ip_putlit("underscore in place of blanks.  Case is ignored, and the",err) ;
  1877.    newline(err) ;
  1878.    ip_putlit("name may be abbreviated to the shortest unique prefix.",err) ;
  1879.    newline(err) ;
  1880.    exit(1) ;
  1881. }
  1882.  
  1883. /***********************************************/
  1884.  
  1885. void select_printer(name)
  1886. char *name ;
  1887. {
  1888.    int i, len, prt = -1 ;
  1889.    
  1890.    len = strlen(name) ;
  1891.    for (i = 0 ; i < len ; i++)        /* convert dashes and underscores to blanks */
  1892.       if (name[i] == '-' || name[i] == '_')
  1893.      name[i] = ' ' ;
  1894.    for (i = 0 ; i < NUM_PRINTERS ; i++)
  1895.       if (strnicmp(name,printers[i].name,len) == 0)
  1896.      if (prt == -1)
  1897.         prt = i ;
  1898.      else
  1899.         fatal("Ambiguous printer name!  Use -P? to list printers.") ;
  1900.    if (prt == -1)
  1901.       fatal("Unknown printer name!  Use -P? to list printers.") ;
  1902.    else
  1903.       printer = &printers[prt] ;
  1904. }
  1905.  
  1906. /***********************************************/
  1907.  
  1908. void add_category_filter_info(filter, str)
  1909. CF_ENUM filter ;
  1910. char *str ;
  1911. /* insert category filter characters into proper buffer, provided they do
  1912.    not appear in other filter buffers
  1913. */
  1914. {
  1915.    static char err_msg[] =
  1916.     "Character \"x\" appears in more than one category filter string";
  1917. #define err_char_pos 11 /* position of x in err_msg */
  1918.    CF_ENUM f ;
  1919.    int i = 0, len = strlen(cf_buffers[filter]) ;
  1920.    char c, errmsg[80] ;
  1921.  
  1922.    while ((c = str[i++]) > ' ' && len < CF_BUFFER_SIZE)
  1923.       {
  1924.       for (f = filter; ; )
  1925.      {
  1926.      if ((f = (f + 1) % CF_ENUM_SIZE) == filter)
  1927.        break; /* all other filters checked */
  1928.      if (strchr(cf_buffers[f], c))
  1929.         {
  1930.         err_msg[err_char_pos] = c ;
  1931.         fatal(err_msg) ;
  1932.         }
  1933.      }
  1934.      cf_buffers[filter][len++] = c;
  1935.       }
  1936. #undef err_char_pos
  1937. }
  1938.  
  1939. /***********************************************/
  1940.  
  1941. FILT_LIST *add_filter_info(list,str)
  1942. FILT_LIST *list ;
  1943. char *str ;
  1944. {
  1945.    FILT_LIST *newfilt ;
  1946.    int len = strlen(str)+1 ;
  1947.    
  1948.    if ((newfilt = (FILT_LIST *)malloc(sizeof(struct filter_list)+len))
  1949.       != NULL)
  1950.       {
  1951.       newfilt->next = list ;
  1952.       memcpy(newfilt->str,str,len) ;
  1953.       strupr(newfilt->str) ;
  1954.       }
  1955.    else
  1956.       fatal("out of memory") ;
  1957.    return newfilt ;
  1958. }
  1959.  
  1960. /***********************************************/
  1961.  
  1962. void build_filter_lists(file)
  1963. char *file ;
  1964. {
  1965.    static char err_msg[] = "Unknown command \"x\" in filter file";
  1966. #define err_char_pos 17 /* position of x in err_msg */
  1967.    IP_FILE *fp ;
  1968.    char buf[MAXLINE] ;
  1969.    int len ;
  1970.    long result ;
  1971.  
  1972.    if ((fp = ip_open_read(file,filter_buf,sizeof(filter_buf))) == NULL)
  1973.       {
  1974.       warning("unable to open filtering file, will print entire list.") ;
  1975.       do_filter = FALSE ;
  1976.       }
  1977.    else /* OK, file is open, so start reading */
  1978.       {
  1979.       do {
  1980.      buf[0] = '\0' ;
  1981.      result = ip_fgets(buf, sizeof(buf), fp) ;
  1982.      len = strlen(buf) ;
  1983.      if (len > 1)
  1984.         {
  1985.         switch (buf[0])
  1986.            {
  1987.            case '+':
  1988.           includes = add_filter_info(includes,buf+1) ;
  1989.           goto include_too ;
  1990.            case '-':
  1991.           excludes = add_filter_info(excludes,buf+1) ;
  1992.           break ;
  1993.            case CF_EXCLUDE_CHAR:
  1994.           add_category_filter_info(CF_EXCLUDE, buf+1) ;
  1995.           break ;
  1996.            case CF_UNCONDITIONAL_CHAR:
  1997.           add_category_filter_info(CF_UNCONDITIONAL, buf+1) ;
  1998.           goto include_too ;
  1999.            case CF_INCLUDE_CHAR:
  2000.           add_category_filter_info(CF_INCLUDE, buf+1) ;
  2001.           goto include_too ;
  2002.            case CF_OVERRIDE_CHAR:
  2003.           add_category_filter_info(CF_OVERRIDE, buf+1) ;
  2004.           break ;
  2005.            case '#':        /* comment lines */
  2006.           break ;
  2007.            default:
  2008.           err_msg[err_char_pos] = buf[0] ;
  2009.           fatal(err_msg) ;
  2010.      include_too:
  2011.           exclude_only = FALSE;
  2012.            }
  2013.         }
  2014.      } while (result != -1) ;
  2015.       ip_close(fp) ;
  2016.       do_filter = TRUE ;
  2017.       }
  2018. #undef err_char_pos
  2019. }
  2020.  
  2021. /***********************************************/
  2022.  
  2023. void write_summary_header(fp,title,show_offsets,show_table)
  2024. IP_FILE *fp ;
  2025. char *title ;
  2026. int show_offsets, show_table ;
  2027. {
  2028.    /* set up the printer */
  2029.    ip_putcstr(&printer->init1,fp) ;
  2030.    ip_putcstr(&printer->init2,fp) ;
  2031.    ip_putcstr(&printer->marginc,fp) ;
  2032.    /* now start writing the actual header */
  2033.    indent_to(show_offsets?8:0,fp) ;
  2034.    ip_putlit("\t\t\t\t",fp) ;
  2035.    ip_puts(title,fp) ;
  2036.    newline(fp) ;
  2037.    indent_to(show_offsets?8:0,fp) ;
  2038.    ip_putlit("\t\t\t\t",fp) ;
  2039.    (*printer->put_line)(fp,strlen(title)) ;
  2040.    newline(fp) ;
  2041.    newline(fp) ;
  2042.    indent_line(fp) ;
  2043.    if (show_offsets)
  2044.       ip_putlit("Offset  ", fp) ;
  2045.    if (show_table)
  2046.       ip_putlit("Table ",fp) ;
  2047.    ip_putlit("INT AH AL", fp) ;
  2048.    if (page_numbers)
  2049.       ip_putlit(" Page", fp) ;
  2050.    ip_putlit("\t\t\tDescription", fp) ;
  2051.    newline(fp) ;
  2052.    indent_line(fp) ;
  2053.    (*printer->put_line)(fp,page_width+(show_offsets?8:0)) ;
  2054.    newline(fp) ;
  2055. }
  2056.  
  2057. /***********************************************/
  2058.  
  2059. static void reset_printer_and_close(fp)
  2060. IP_FILE *fp ;
  2061. {
  2062.    ip_putcstr(&printer->term1,fp) ;
  2063.    ip_putcstr(&printer->term2,fp) ;
  2064.    ip_close(fp) ;
  2065. }
  2066.  
  2067. /***********************************************/
  2068.  
  2069. int _Cdecl main(argc,argv)
  2070. int argc ;
  2071. char *argv[] ;
  2072. {
  2073.    int lines_per_page = -1 ;
  2074.    int total_lines = -1 ;
  2075.    int use_FF = TRUE ;
  2076.    int last_line ;
  2077.    int body_lines ;
  2078.    char *typeface = NULL ;
  2079.    char *summary_file = NULL ;
  2080.    char *table_file = NULL ;
  2081.    char *formats_file = NULL ;
  2082.    char *filter_file = NULL ;
  2083.    char *last_page_num ;
  2084.  
  2085.    err = ip_fdopen(2,stderr_buf,sizeof(stderr_buf),sizeof(stderr_buf),1) ;
  2086.    ip_putlit("INTPRINT v", err) ;
  2087.    ip_putlit(VERSION, err) ;
  2088.    ip_putlit(" by Ralf Brown and others.  Donated to the Public Domain.",err) ;
  2089.    newline(err) ;
  2090.    ip_flush(err) ;
  2091.    if (argc == 1 && isatty(0))
  2092.       usage() ;      /* give help if invoked with no args and keybd input */
  2093.    while (argc >= 2 && argv[1][0] == '-')
  2094.       {
  2095.       switch (argv[1][1])
  2096.      {
  2097.      case 'B':
  2098.         printer_bold = TRUE ;
  2099.         /* fall through to -b */
  2100.      case 'b':
  2101.         boldface = TRUE ;
  2102.         break ;
  2103.      case 'd':
  2104.         duplex = TRUE ;
  2105.         break ;
  2106.      case 'e':
  2107.         indent = 8 ;
  2108.         page_width = 87 ;  /* 96 - indent - 1 right margin */
  2109.         break ;
  2110.      case 'f':
  2111.         formats_file = argv[1]+2 ;
  2112.         break ;
  2113.      case 'F':
  2114.         filter_file = argv[1]+2 ;
  2115.         break ;
  2116.      case 'H':   /* page headers */
  2117.         do_headers = TRUE ;
  2118.         break ;
  2119.      case 'i':
  2120.         indent = atoi(argv[1]+2) ;
  2121.         break ;
  2122.      case 'I':
  2123.         IBM_chars = TRUE ;
  2124.         break ;
  2125.      case 'k':
  2126.         keep_divider_lines = TRUE ;
  2127.         break ;
  2128.      case 'l':
  2129.         lines_per_page = atoi(argv[1]+2) ;
  2130.         break ;
  2131.      case 'L':
  2132.         total_lines = atoi(argv[1]+2) ;
  2133.         break ;
  2134.      case 'm':
  2135.         multi_file = TRUE ;
  2136.         break ;
  2137.      case 'n':
  2138.         pages_printed = atoi(argv[1]+2) ;
  2139.         break ;
  2140.      case 'P':
  2141.         if (argv[1][2] == '?')
  2142.            display_printers() ;
  2143.         else
  2144.            select_printer(argv[1]+2) ;
  2145.         break ;
  2146.      case 'p':
  2147.         page_numbers = TRUE ;
  2148.         break ;
  2149.      case 'r':
  2150.         first_page = atoi(argv[1]+2) ;
  2151.         last_page_num = strchr(argv[1]+2, ':') ;
  2152.         last_page = last_page_num ? atoi(last_page_num+1) : 0 ;
  2153.         if (last_page == 0)
  2154.            last_page = ~0 ;
  2155.         break ;
  2156.      case 's':
  2157.         summary_file = argv[1]+2 ;
  2158.         break ;
  2159.      case 't':
  2160.         typeface = argv[1]+2 ;
  2161.         break ;
  2162.      case 'T':
  2163.         table_file = argv[1]+2 ;
  2164.         break ;
  2165.      case 'V':
  2166.         show_offsets = IBM_chars = TRUE ;
  2167.         break ;
  2168.      case 'w':
  2169.         widow_length = atoi(argv[1]+2) ;
  2170.         break ;
  2171.      case 'x':
  2172.         include_index_lines = TRUE ;
  2173.         break ;
  2174.      default:
  2175.         usage() ;
  2176.      }
  2177.       argv++ ;
  2178.       argc-- ;
  2179.       }
  2180.    if (printer == NULL)
  2181.       select_printer("default") ;
  2182.    /* apply any necessary overrides to parameters */
  2183.    if (printer->indent != -1)
  2184.       indent = printer->indent ;
  2185.    if (lines_per_page < 0)
  2186.       lines_per_page = printer->lines_per_page ;
  2187.    if (total_lines <= 0)
  2188.       total_lines = printer->page_length ;
  2189.    if (page_width <= 0)
  2190.       page_width = printer->page_width ;
  2191.    if (show_offsets && page_width < 80)
  2192.       page_width = 80 ;
  2193.    if (printer->flag)
  2194.       *(printer->flag) = TRUE ;
  2195.    if (cstrlen(&printer->bold_on) == 0)     /* control sequences for bold? */
  2196.       printer_bold = FALSE ;        /* if not, don't try to use them */
  2197.    /* build the indent string */
  2198.    if (indent)
  2199.       {
  2200.       char *t ;
  2201.       int ind = indent ;
  2202.  
  2203.       indent_len = indent/8 + indent%8 ;
  2204.       t = indent_string = (char *)malloc(indent_len+1) ;
  2205.       while (ind >= 8)
  2206.      {
  2207.      *t++ = '\t' ;
  2208.      ind -= 8 ;
  2209.      }
  2210.       while (ind > 0)
  2211.      {
  2212.      *t++ = ' ' ;
  2213.      ind-- ;
  2214.      }
  2215.       }
  2216.    /* open the summary file, if any */
  2217.    if (summary_file && *summary_file)
  2218.       if ((summary = ip_open_write(summary_file,!pages_printed,summary_buf,
  2219.                    sizeof(summary_buf)))
  2220.         != NULL)
  2221.      do_summary = TRUE ;
  2222.       else
  2223.      warning("unable to open summary file") ;
  2224.    /* open the table index file, if any */
  2225.    if (table_file && *table_file)
  2226.       if ((tables = ip_open_write(table_file,!pages_printed,tables_buf,
  2227.                   sizeof(tables_buf)))
  2228.         != NULL)
  2229.      do_tables = TRUE ;
  2230.       else
  2231.      warning("unable to open table index file") ;
  2232.    /* open the data formats file, if any */
  2233.    if (formats_file && *formats_file)
  2234.       if ((formats = ip_open_write(formats_file,!pages_printed,formats_buf,
  2235.                    sizeof(formats_buf)))
  2236.         != NULL)
  2237.      do_formats = TRUE ;
  2238.       else
  2239.      warning("unable to open formats file") ;
  2240.    need_summary = (do_summary || do_formats || do_tables) ;
  2241.    /* initialize filtering data, if specified */
  2242.    if (filter_file && *filter_file)
  2243.       build_filter_lists(filter_file) ;
  2244.    if (total_lines <= lines_per_page)
  2245.       {
  2246.       total_lines = lines_per_page ;
  2247.       use_FF = TRUE ;
  2248.       }
  2249.    else
  2250.       use_FF = FALSE ;
  2251.    if (argc == 2 || argc == 3)
  2252.       {
  2253.       input_file = argv[1] ;
  2254.       input_file_namelen = strlen(input_file) ;
  2255.       if ((infile = ip_open_read(input_file,infile_buf,sizeof(infile_buf))) == NULL)
  2256.      fatal("unable to open input file") ;
  2257.       if (argc == 3)
  2258.      {
  2259.      outfile = ip_open_write(argv[2],!pages_printed,outfile_buf,
  2260.                  sizeof(outfile_buf)) ;
  2261.      if (outfile == NULL)
  2262.         fatal("unable to open output file") ;
  2263.      }
  2264.       else
  2265.      outfile = ip_open_write("",0,outfile_buf,sizeof(outfile_buf)) ;
  2266.       }
  2267.    else
  2268.       usage() ;
  2269.    if (lines_per_page > MAXPAGE)
  2270.       {
  2271.       ip_putlit("Surely you jest!  I can't handle pages that long.",err) ;
  2272.       newline(err) ;
  2273.       newline(err) ;
  2274.       usage() ;
  2275.       }
  2276.    else if (lines_per_page == 0) /* infinite page? */
  2277.       {
  2278.       widow_length = 0 ;
  2279.       if (total_lines <= 0)
  2280.      total_lines = MAXPAGE ;
  2281.       lines_per_page = total_lines ;
  2282.       use_FF = do_headers = page_numbers = FALSE ;
  2283.       }
  2284.    else
  2285.       {
  2286.       if (lines_per_page < 20)
  2287.      {
  2288.      ip_putlit("Surely your printer can handle at least 20 lines per page!",
  2289.            err) ;
  2290.      newline(err) ;
  2291.      ip_putlit("Adjusting page length....",err) ;
  2292.      newline(err) ;
  2293.      lines_per_page = 20 ;
  2294.      }
  2295.       if (widow_length < 3 || widow_length > lines_per_page / 2)
  2296.      {
  2297.      ip_putlit("Widow lines (-w) must be set to at least 3 and at most one-half of the",err) ;
  2298.      newline(err) ;
  2299.      ip_putlit("page length.  Using default of 8 lines.",err) ;
  2300.      newline(err) ;
  2301.      widow_length = 8 ;
  2302.      }
  2303.       }
  2304.    /* set up the printer */
  2305.    ip_putcstr(&printer->init1,outfile) ;
  2306.    ip_putcstr(&printer->init2,outfile) ;
  2307.    if (printer->set_typeface)
  2308.       (*printer->set_typeface)(outfile,typeface) ;
  2309.    if (duplex)
  2310.       {
  2311.       ip_putcstr(&printer->duplex_on,outfile) ;
  2312.       if (pages_printed & 1)          /* next page odd or even? */
  2313.      ip_putcstr(&printer->marginl,outfile) ;    /* even */
  2314.       else
  2315.      ip_putcstr(&printer->marginr,outfile) ;    /* odd */
  2316.       }
  2317.    else
  2318.       ip_putcstr(&printer->marginc,outfile) ;    /* non-duplex, so center */
  2319.    /* start the auxiliary files if this is the first part processed */
  2320.    if (pages_printed == 0)
  2321.       {
  2322.       /* start the summary file */
  2323.       if (do_summary)
  2324.      write_summary_header(summary,"Interrupt Summary",show_offsets,FALSE) ;
  2325.       /* start the table index file */
  2326.       if (do_tables)
  2327.      write_summary_header(tables,"Table Summary",show_offsets,TRUE) ;
  2328.       /* start the data formats file */
  2329.       if (do_formats)
  2330.      write_summary_header(formats,"Data Structure Formats",FALSE,FALSE) ;
  2331.       }
  2332.    if (page_numbers)
  2333.       body_lines = lines_per_page - 2 ;
  2334.    else
  2335.       body_lines = lines_per_page ;
  2336.    if (do_headers)
  2337.       body_lines -= 2 ;
  2338.    last_line = 0 ;
  2339.    while (!out_of_files)
  2340.       {
  2341.       fill_buffer(last_line,body_lines) ;
  2342.       last_line = find_page_break(body_lines) ;
  2343.       print_buffer(last_line,body_lines,lines_per_page,total_lines,use_FF) ;
  2344.       }
  2345.    if (last_line < body_lines)
  2346.       {
  2347.       int i ;
  2348.       
  2349.       for (i = last_line ; i < body_lines ; i++)
  2350.      {
  2351.      strcpy(buffer[i-last_line], buffer[i]) ;
  2352.      line_offsets[i-last_line] = line_offsets[i] ;
  2353.      }
  2354.       print_buffer(body_lines-last_line,body_lines,lines_per_page,total_lines,
  2355.            use_FF) ;
  2356.       }
  2357.    ip_close(infile) ;
  2358.    /* reset the printer */
  2359.    reset_printer_and_close(outfile) ;
  2360.    ip_puts(itoa(pages_printed, num, 10), err) ;
  2361.    ip_putlit(" pages", err) ;
  2362.    if (do_summary)
  2363.       reset_printer_and_close(summary) ;
  2364.    if (do_tables)
  2365.       {
  2366.       ip_putlit(", ", err) ;
  2367.       ip_puts(itoa(prev_table, num, 10), err) ;
  2368.       ip_putlit(" tables", err) ;
  2369.       reset_printer_and_close(tables) ;
  2370.       }
  2371.    if (do_formats)
  2372.       reset_printer_and_close(formats) ;
  2373.    newline(err) ;
  2374.    ip_close(err) ;
  2375.    return 0 ;
  2376. }
  2377.